package com.focus.xyz.core.common.keyword;

import com.focus.xyz.core.utils.prop.ConfigPropInfo;
import com.google.common.base.Function;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by chenmeng on 2016/4/28.
 */
public class Action{
    private static transient Logger logger = LoggerFactory.getLogger(Action.class);
    private WebDriver driver;
    private Action(){

    }

    public Action(WebDriver driver){
        this.driver = driver;
    }

    /**
     * 打开页面,默认最大化窗口
     * @param url
     * @throws Exception
     */
    public void open(String url) throws Exception {
        open(url,null, true);
    }

    /**
     * 打开页面，设置尺寸
     * @param url
     * @param isMax
     * @throws Exception
     */
    public void open(String url, Dimension size,boolean isMax) throws Exception {
        driver.get(url);
        if (isMax) {
            driver.manage().window().maximize();
            waitForPageLoad();
        }else{
            driver.manage().window().setSize(size);
        }
    }

    /**
     * 判断页面是否加载完成
     * @return
     * @throws Exception
     */
    public boolean isLoaded() throws Exception {
        return getJsExcutor().executeScript("return document.readyState").equals("complete");
    }

    /**
     * input框 输入文本
     * @param input
     * @param text
     * @throws Exception
     */
    public void inputText(WebElement input, String text) throws Exception {
        if(isElementExist(input)){
            if (input.isDisplayed()&&input.isEnabled()) {
                input.clear();
                input.sendKeys(text);
            }
        }else{
            pause(1000l);
            if (input.isDisplayed()&&input.isEnabled()) {
                input.clear();
                input.sendKeys(text);
            }
        }
    }

    /**
     * 单击元素
     * @param element
     */
    public void click(WebElement element) {
        click(element, 0);
    }


    private void click(WebElement element, long waitTime) {
        WebElement webElement = waitExplicit(waitTime).until(ExpectedConditions.elementToBeClickable(element));
        webElement.click();
    }

    private WebDriverWait waitExplicit(long waitTime) {
        WebDriverWait wait = null;
        if (waitTime == 0) {
            wait = new WebDriverWait(driver, ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        } else {
            wait = new WebDriverWait(driver, TimeUnit.MILLISECONDS.toSeconds(waitTime));
        }
        return wait;
    }

    /**
     * 双击元素
     * @param element
     */
    public void doubleClick(WebElement element) {
        doubleClick(element, 0);
    }

    /**
     * 双击元素并设置显示等待时间
     * @param element
     * @param waitTime
     */
    public void doubleClick(WebElement element, long waitTime) {
        WebElement webElement = waitExplicit(waitTime).until(ExpectedConditions.elementToBeClickable(element));
        Actions actions = new Actions(driver);
        actions.doubleClick(webElement).build().perform();
    }

    /**
     * 右击元素
     * @param el
     * @param waitTime
     */
    public void contextClick(WebElement el,long waitTime){
        WebElement webElement = waitExplicit(waitTime).until(ExpectedConditions.elementToBeClickable(el));
        Actions actions = new Actions(driver);
        actions.contextClick(webElement).build().perform();
    }

    /**
     * 线程等待
     * @param millis
     */
    public void pause(long millis) {
        pause(millis, TimeUnit.MILLISECONDS);
    }

    public void pause(long time, TimeUnit unit) {
        try {
            Thread.sleep(unit.toMillis(time));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 选择checkbox
     * @param webElement
     * @throws Exception
     */
    public void selectCheckBox(WebElement webElement) throws Exception {
        if (!webElement.isSelected()) {
            webElement.click();
        }
    }

    /**
     * 取消选择checkbox
     * @param webElement
     * @throws Exception
     */
    public void deselectCheckBox(WebElement webElement) throws Exception {
        if (webElement.isSelected()) {
            webElement.click();
        }
    }

    /**
     * 判断页面中是否出现了指定的内容
     * @param target
     * @return
     * @throws Exception
     */
    public boolean contains(String target) throws Exception {
        return driver.getPageSource().contains(target);
    }

    /**
     * 获取指定元素的文本内容，如果元素不存在返回空
     * @param by
     * @return
     * @throws Exception
     */
    public String getText(By by) throws Exception{
        waitForElementPresent(by);
        if(isElementExsit(by)){
            return driver.findElement(by).getText().trim();
        }else{
            return "";
        }
    }

    /**
     * 等待页面元素出现
     * @param by
     * @throws Exception
     */
    public void waitForElementPresent(By by) throws Exception{
        WebDriverWait wait = new WebDriverWait(driver, ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

    /**
     * 断言页面内容，出现指定内容时成功，没有出现则失败
     * @param target
     * @throws Exception
     */
    public void assertStringTrue(String target) throws Exception{
        Assert.assertTrue(contains(target));
    }

    /**
     * 断言页面内容，出现指定内容时失败，没有出现则成功
     * @param target
     * @throws Exception
     */
    public void assertStringFalse(String target) throws Exception{
        Assert.assertFalse(contains(target));
    }

    /**
     * 断言成功
     * @throws Exception
     */
    public void success() throws Exception {
        Assert.assertTrue(true);
    }

    /**
     * 断言失败
     * @param target
     * @throws Exception
     */
    public void fail(String target) throws Exception {
        Assert.fail(target);
    }

    /**
     * 等待页面加载完成，
     * @throws Exception
     */
    public void waitForPageLoad() throws Exception {
        WebDriverWait wait = new WebDriverWait(driver, ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        wait.until(isPageLoaded());
    }

    /**
     * 等待页面中所有ajax请求完成
     * @throws Exception
     */
    public void waitForAjax() throws Exception{
        WebDriverWait   wait  =  new WebDriverWait(driver,ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        wait.until(new ExpectedCondition<Boolean>(){
            public Boolean apply(WebDriver driver){
                Boolean flag = false;
                try {
                    flag = (Boolean) getJsExcutor().executeScript("return jQuery.active == 0");
                } catch (Exception e) {
                }
                return flag;
            }
        });
    }

    /**
     * 等待alert窗口出现
     * @throws Exception
     */
    public void waitForAlert() throws Exception{
        WebDriverWait   wait  =  new WebDriverWait(driver, ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        wait.until(new ExpectedCondition<Boolean>(){
            public Boolean apply(WebDriver driver){
                Boolean flag = false;
                try {
                    driver.switchTo().alert();
                    flag = true;
                } catch (NoAlertPresentException Ex) {
                    flag = false;
                }
                return flag;
            }
        });
    }

    /**
     * 等待alert窗口出现
     * @throws Exception
     */
    public void waitForAlert1() throws Exception{
        WebDriverWait   wait  =  new WebDriverWait(driver,ConfigPropInfo.DRIVER_EXPLICIT_WAIT);
        wait.until(ExpectedConditions.alertIsPresent());
    }


    private Function<WebDriver, Boolean> isPageLoaded() {
        return new Function<WebDriver, Boolean>() {
            public Boolean apply(WebDriver driver) {
                boolean flag = false;
                try {
                    flag = StringUtils.equalsIgnoreCase((String) getJsExcutor().executeScript("return document.readyState"), "complete");
                } catch (Exception e) {
                    flag = false;
                }
                return flag;
            }
        };
    }

    /**
     * 根据定位器判断元素是否存在
     * @param locator
     * @return
     * @throws Exception
     */
    public boolean isElementExsit(By locator) throws Exception {
        boolean flag = false;
        try {
            WebElement element = driver.findElement(locator);
            flag = null != element;
        } catch (NoSuchElementException e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 判断页面元素是否存在
     * @param element
     * @return
     * @throws Exception
     */
    public boolean isElementExist(WebElement element) throws Exception{
        boolean flag = false;
        try {
            element.getTagName();
            flag = true;
        } catch (NoSuchElementException e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 切换到frame，iframe
     * @param frame
     * @throws Exception
     */
    public void switchToFrame(WebElement frame) throws Exception {
        driver.switchTo().frame(frame);
    }

    /**
     * 获取JavascriptExecutor
     * @return
     * @throws Exception
     */
    public JavascriptExecutor getJsExcutor() throws Exception {
        return (JavascriptExecutor) driver;
    }

    /**
     * 获取driver
     * @return
     * @throws Exception
     */
    public WebDriver getDriver() throws Exception {
        return driver;
    }

    /**
     * alert 确定
     * @throws Exception
     */
    public void acceptAlert() throws Exception {
        waitForAlert();
        driver.switchTo().alert().accept();
    }

    /**
     * alert 取消
     * @throws Exception
     */
    public void dismissAlert() throws Exception {
        waitForAlert();
        driver.switchTo().alert().dismiss();
    }

    /**
     * 判断alert是否出现
     * @return
     * @throws Exception
     */
    public boolean isAlertPresent() throws Exception {
        try {
            driver.switchTo().alert();
            return true;
        } catch (NoAlertPresentException Ex) {
            return false;
        }
    }

    /**
     * 根据选项值 选择下拉框
     * @param e
     * @param value
     * @throws Exception
     */
    public void select(WebElement e, String value) throws Exception {
        /*WebDriverWait wait = new WebDriverWait(driver,5000l);
        wait.until(ExpectedConditions.elementToBeSelected(e));*/
        Select select = new Select(e);
        select.selectByVisibleText(value);
    }

    /**
     * 鼠标滑过元素
     * @param element
     * @throws Exception
     */
    public void mouseOver(WebElement element) throws Exception {
        Actions builder = new Actions(driver);
        builder.moveToElement(element);
        builder.perform();
    }

    /**
     * 页面滚动到元素指定位置
     * @param element
     * @throws Exception
     */
    public void scrollTo(WebElement element) throws Exception{
//        getJsExcutor().executeScript("arguments[0].scrollIntoView();", element);
//        getJsExcutor().executeScript("window.scrollTo(0,Math.max(document.documentElement.scrollHeight," + "document.body.scrollHeight,document.documentElement.clientHeight));");
        getJsExcutor().executeScript("arguments[0].scrollIntoViewIfNeeded(true);", element);
    }

    /**
     * 页面滚动到指定位置
     * @param driver
     * @param height 相对于页面顶部的高度--像素
     */
    public void setScroll(WebDriver driver,int height){
        try {
            String setscroll = "document.documentElement.scrollTop=" + height;
            JavascriptExecutor jse=(JavascriptExecutor) driver;
            jse.executeScript(setscroll);
        } catch (Exception e) {
            logger.error("Fail to set the scroll.");
        }
    }

    /**
     * 页面刷新
     * @throws Exception
     */
    public void refresh() throws Exception {
        driver.navigate().refresh();
        waitForPageLoad();
    }

    /**
     * 切换到window
     * @param url
     * @param isMax
     * @throws Exception
     */
    public void switchToWindowByUrl(String url,boolean isMax) throws Exception{
        String currentHandle = driver.getWindowHandle();
        Set<String> handles = driver.getWindowHandles();
        for (String s : handles) {
            if (s.equals(currentHandle))
                continue;
            else {
                driver.switchTo().window(s);
                if(isMax){
                    driver.manage().window().maximize();
                }
                if (driver.getCurrentUrl().contains(url)) {
                    logger.debug("Switch to window: "
                            + driver.getCurrentUrl() + " successfully!");
                    break;
                } else
                    continue;
            }
        }
    }

    /**
     * 当前window关闭 切换到父窗口
     * @param url
     */
    public void switchToParentWindow(String url) {
        try {
            Set<String> handles = driver.getWindowHandles();
            for (String s : handles) {
                driver.switchTo().window(s);
                if (driver.getCurrentUrl().contains(url)) {
                    logger.debug("Switch to window: "
                            + driver.getCurrentUrl() + " successfully!");
                    break;
                } else
                    continue;
            }
        } catch (NoSuchWindowException e) {
            logger.error("切换异常：" + driver.getCurrentUrl());
        }
        logger.info("当前窗口URL:" + driver.getCurrentUrl());
    }

    /**
     * 页面滚动到指定位置
     * @param px
     * @throws Exception
     */
    public void scrollTo(int px) throws Exception{
        getJsExcutor().executeScript("document.documentElement.scrollTop = " + px);
    }

    /**
     * 移动到指定元素位置
     * @param target
     * @throws Exception
     */
    public void moveToElement(WebElement target) throws Exception{
        Actions actions = new Actions(driver);
        actions.moveToElement(target).perform();
    }

    /**
     * 设置元素属性
     * @param element
     * @param attrName
     * @param value
     * @throws Exception
     */
    public void setAttribute(WebElement element,String attrName,String value) throws Exception{
        getJsExcutor().executeScript("arguments[0].setAttribute(arguments[1],arguments[2])",element,attrName,value);
    }

    /**
     * 删除元素属性
     * @param element
     * @param attrName
     * @throws Exception
     */
    public void removeAttribute(WebElement element,String attrName) throws Exception{
        getJsExcutor().executeScript("arguments[0].removeAttribute(arguments[1])",element,attrName);
    }

    /**
     * javascript 点击事件，对于有些元素selenium无法点击，可以通过js点击
     * @param el
     * @throws Exception
     */
    public void jsClick(WebElement el) throws Exception{
        getJsExcutor().executeScript("arguments[0].click()",el);
    }

    /**
     * 键盘事件，点击esc按钮
     * @throws Exception
     */
    public void esc() throws Exception{
        Robot robot = new Robot();
        robot.keyPress(KeyEvent.VK_ESCAPE);
    }

    /**
     * 点击tab键
     * @throws Exception
     */
    public void tab() throws Exception{
        Robot robot = new Robot();
        robot.keyPress(KeyEvent.VK_TAB);
    }

    /**
     * 页面截图
     * @param path
     */
    public void capScreen(String path) {
        File scrFile = (File)((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(scrFile, new File(path),false);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}
